// NB :: ALL ADDITION IN THIS CLASS IS REPLACED WITH XOR TO NEGATE CARRY
public class Convo {

  public static int[][] convo(int n) {
    return matrixAdd(scalarShift(convo0(n), 1), convo1(n));
  }

  public static int[][] convo0(int n) {
    return convo(n, 2);
  }

  public static int[][] convo1(int n) {
    return convo(n, 1);
  }

  public static int[][] convo(int n, int s) {
    int[][] matrix = new int[n][n];
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        matrix[i][j] = ((i == j) || (i == j+s) || (i == j+3)) ? 1 : 0;
    return matrix;
  }

  public static int[][] matrixAdd(int[][] a, int[][] b) {
    if (a.length != b.length)
      throw new IllegalArgumentException("matrix dimension mismatch");
    int[][] result = new int[a.length][];
    for (int i = 0; i < result.length; i++) {
      if (a[i].length != b[i].length)
        throw new IllegalArgumentException("matrix dimension mismatch");
      result[i] = new int[a[i].length];
      for (int j = 0; j < result[i].length; j++)
        result[i][j] = a[i][j] ^ b[i][j];
    }
    return result;
  }

  public static int[][] scalarShift(int[][] a, int b) {
    int [][] result = new int[a.length][];
    for (int i = 0; i < result.length; i++) {
      result[i] = new int[a[i].length];
      for (int j = 0; j < result[i].length; j++)
        result[i][j] = a[i][j] << b;
    }
    return result;
  }

  public static int[] convoApply(int[] a) {
    return apply(convo(a.length), a);
  }

  public static int[] apply(int[][] c, int[] x) {
    int [] y = new int[c.length];
    for (int i = 0; i < y.length; i++)
      y[i] = dot(c[i], x);
    return y;
  }

  public static int dot(int[] a, int[] b) {
    if (a.length != b.length)
      throw new IllegalArgumentException("vector dimension mismatch");
    int dp = 0;
    for (int i = 0; i < a.length; i++)
      dp ^= a[i] * b[i];
    return dp;
  }

  public static int[] stringToOneBitIntArray(String a) {
    char[] cs = a.toCharArray();
    int[] is = new int[cs.length];
    for (int i = 0; i < is.length; i++)
      if (cs[i] == '0')
        is[i] = 0;
      else if (cs[i] == '1')
        is[i] = 1;
      else
        throw new IllegalArgumentException("not a bit string: " + a);
    return is;
  }

  public static String twoBitIntArrayToString(int[] a) {
    StringBuilder sb = new StringBuilder();
    for (int i : a)
      if (i == 0)
        sb.append("00");
      else if (i == 1)
        sb.append("01");
      else if (i == 2)
        sb.append("10");
      else if (i == 3)
        sb.append("11");
      else
        throw new IllegalArgumentException("integer larger than 2 bits: " + i);
    return sb.toString();
  }

  public static void main(String[] argVector) {
    for (String s : argVector) {
      System.out.println(twoBitIntArrayToString(convoApply(stringToOneBitIntArray(s))));
    }
  }

}
